package com.clt.ess.utils;

import java.io.*;
import java.math.BigInteger;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;

import com.clt.ess.crypt.ExDataStru;
import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Choice;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1String;
import org.bouncycastle.asn1.BERTags;
import org.bouncycastle.asn1.DERApplicationSpecific;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DEREncodableVector;
import org.bouncycastle.asn1.DERGeneralizedTime;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.x509.Extension;

import sun.misc.BASE64Decoder;

import static com.clt.ess.gjzw.utils.CypherUtil.signValue;
import static com.clt.ess.gjzw.utils.CypherUtil.signValueAsn1;
import static com.clt.ess.utils.Base64Utils.ESSGetBase64Encode;
import static com.clt.ess.utils.Base64Utils.readBin2Image;

public class MakeAsn1Seal {
	private static ASN1EncodableVector CreateSealHead(String sealTag,int iVersion,String makerID){
		ASN1EncodableVector v = new ASN1EncodableVector();
		
		DERIA5String ia5String = new DERIA5String(sealTag);
		v.add(ia5String);
		v.add(new ASN1Integer(iVersion));
		
		DERIA5String ia5String2 = new DERIA5String(makerID);
		v.add(ia5String2);
		
		return v;
	}
	
	private static ASN1EncodableVector CreatePictureInfo(String sPicType,byte[] bPic,int iW,int iH){
		ASN1EncodableVector v = new ASN1EncodableVector();
		DERIA5String ia5String = new DERIA5String(sPicType);
		v.add(ia5String);
		DEROctetString octString = new DEROctetString(bPic);
		v.add(octString);
		v.add(new ASN1Integer(iW));
		v.add(new ASN1Integer(iH));
		return v;
	}
	
	private static ASN1EncodableVector CreatePorpertyInfo(int iSealType,String sSealName,int iListType,ASN1EncodableVector certList,String sealMakeDate,String sealBeginDate,String sealEndDate){
		ASN1EncodableVector v = new ASN1EncodableVector();
		v.add(new ASN1Integer(iSealType));
		DERUTF8String utf8String = new DERUTF8String(sSealName);
		v.add(utf8String);
		v.add(new ASN1Integer(iListType));
		DERSequence certs = new DERSequence(certList);
		v.add(certs);
		DERGeneralizedTime t1 = new DERGeneralizedTime(sealMakeDate);
		DERGeneralizedTime t2 = new DERGeneralizedTime(sealBeginDate);
		DERGeneralizedTime t3 = new DERGeneralizedTime(sealEndDate);
		v.add(t1);
		v.add(t2);
		v.add(t3);
		return v;
	}
	
	
	private static ASN1EncodableVector CreateCertList(Vector<String> vCert){
		ASN1EncodableVector v = new ASN1EncodableVector();
		BASE64Decoder d64 = new BASE64Decoder();
		for(int i=0;i<vCert.size();i++)
		{
			String sCert = vCert.elementAt(i);
			try {
				byte[] bCert = d64.decodeBuffer(sCert);
				DEROctetString octString = new DEROctetString(bCert);
				v.add(octString);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return v;
	}
	
	
	private static ASN1EncodableVector CreateSealInfo(ASN1EncodableVector header,String sealID,ASN1EncodableVector property,ASN1EncodableVector picInfo,ASN1EncodableVector extData ){
		ASN1EncodableVector v = new ASN1EncodableVector();
		DERSequence derSeq = new DERSequence(header);
		v.add(derSeq);
		DERIA5String ia5String = new DERIA5String(sealID);
		v.add(ia5String);
		derSeq = new DERSequence(property);
		v.add(derSeq);
		derSeq = new DERSequence(picInfo);
		v.add(derSeq);
//		derSeq = new DERSequence(extData);
//		v.add(derSeq);
		return v;
	}
	
	private static ASN1EncodableVector CreateExData(Vector<ExDataStru> ve) throws UnsupportedEncodingException{
		ASN1EncodableVector vEx = new ASN1EncodableVector();
		for(int i=0;i<ve.size();i++){
			ExDataStru exStru = ve.elementAt(i);
			
			String oidSEx = exStru.oid;
			ASN1ObjectIdentifier oidex = new ASN1ObjectIdentifier(oidSEx);
			String octsEx = exStru.sData;
			DEROctetString octStringEx = new DEROctetString(octsEx.getBytes("utf8"));
			Extension ex1 = new Extension(oidex, exStru.blOption, octStringEx);
			vEx.add(ex1);
		}
		return vEx;
	}
	
	
	public static byte[] CreateSeal(
			String 		sealTag,                    //电子印章标识
			int 		iVersion,                    //版本号
			String		sMakerID,                    //印章厂商ID
			String 		sSealID,                    //印章唯一赋码
			int			iSealType,                    //印章类型
			String		sSealName,                    //印章名称
			int			iListType,                    //证书列表类型
			Vector<String>	vCert,                    //可签证书列表
			String		sMakeDate,                    //制作日期
			String		sValidBegin,                //印章有效期起始
			String		sValidEnd,                    //印章有效期终止
			String		sPicType,                    //图像类型
			byte[]		bPicData,                    //图像数据
			int			iPicWidth,                    //图像显示宽度（毫米）
			int			iPicHeight,                    //图像显示高度（毫米)
			Vector<ExDataStru> exDatas,                //扩展字段,
			byte[]		bMakerCert,                    //制章者证书
			String		signAlgID                    //签名算法标识
			) throws IOException {
		
		//印章头
		ASN1EncodableVector header = CreateSealHead(sealTag,iVersion,sMakerID);
		//可签印章列表
		ASN1EncodableVector certList = CreateCertList(vCert);
		
		ASN1EncodableVector propInfo = CreatePorpertyInfo(iSealType,sSealName,iListType,certList,sMakeDate,sValidBegin,sValidEnd);
		
		ASN1EncodableVector picInfo = CreatePictureInfo(sPicType,bPicData,iPicWidth,iPicHeight);
		
		ASN1EncodableVector extensionDates = null;
		try {
			extensionDates = CreateExData(exDatas);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			return null;
		}
		ASN1EncodableVector sealInfo = CreateSealInfo(header,sSealID,propInfo,picInfo,extensionDates);
		DERSequence der = new DERSequence(sealInfo);
		byte[] bSealInfo = null;
		try {
			bSealInfo = der.getEncoded("DER");
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}

		//uk信息文件
		//readBin2Image(bSealInfo,"/data/sealInfo.clt");

		//调用加密机，对  bSealInfo  签名，返回的就是印章的签名值
		byte[] bSignVal = signValueAsn1(bSealInfo);


	//	readBin2Image(bSignVal,"/data/SignVal.clt");
//		if(true){
//			File f = new File("/tmp/SignVal.clt");
//			FileOutputStream fos = new FileOutputStream(f);
//			fos.write(bSignVal);
//			fos.close();
//
//
//			f = new File("/tmp/sealInfo.clt");
//			fos = new FileOutputStream(f);
//			fos.write(bSealInfo);
//			fos.close();
//		}




		ASN1EncodableVector seal = new ASN1EncodableVector();
		seal.add(new DERSequence(sealInfo));
		seal.add(new DEROctetString(bMakerCert));
		seal.add(new ASN1ObjectIdentifier(signAlgID));
		seal.add(new DERBitString(bSignVal));

		der = new DERSequence(seal);

		try {
			byte[] b = der.getEncoded();
//			if(true){
//				File f = new File("/tmp/sealdata.clt");
//				FileOutputStream fos = new FileOutputStream(f);
//				fos.write(b);
//				fos.close();
//			}
			return b;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	//20190302143029Z
	public static String getbSignVal(
			String 		sealTag,                    //电子印章标识
			int 		iVersion,                    //版本号
			String		sMakerID,                    //印章厂商ID
			String 		sSealID,                    //印章唯一赋码
			int			iSealType,                    //印章类型
			String		sSealName,                    //印章名称
			int			iListType,                    //证书列表类型
			Vector<String>	vCert,                    //可签证书列表
			String		sMakeDate,                    //制作日期
			String		sValidBegin,                //印章有效期起始
			String		sValidEnd,                    //印章有效期终止
			String		sPicType,                    //图像类型
			byte[]		bPicData,                    //图像数据
			int			iPicWidth,                    //图像显示宽度（毫米）
			int			iPicHeight,                    //图像显示高度（毫米)
			Vector<ExDataStru> exDatas,                //扩展字段,
			byte[]		bMakerCert,                    //制章者证书
			String		signAlgID                    //签名算法标识
	){

		//印章头
		ASN1EncodableVector header = CreateSealHead(sealTag,iVersion,sMakerID);
		//可签印章列表
		ASN1EncodableVector certList = CreateCertList(vCert);

		ASN1EncodableVector propInfo = CreatePorpertyInfo(iSealType,sSealName,iListType,certList,sMakeDate,sValidBegin,sValidEnd);

		ASN1EncodableVector picInfo = CreatePictureInfo(sPicType,bPicData,iPicWidth,iPicHeight);

		ASN1EncodableVector extensionDates = null;
		try {
			extensionDates = CreateExData(exDatas);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			return null;
		}
		ASN1EncodableVector sealInfo = CreateSealInfo(header,sSealID,propInfo,picInfo,extensionDates);
		DERSequence der = new DERSequence(sealInfo);
		byte[] bSealInfo = null;
		try {
			bSealInfo = der.getEncoded("DER");
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		//调用加密机，对  bSealInfo  签名，返回的就是印章的签名值
		return ESSGetBase64Encode(signValue(bSealInfo));
	}
}